package com.gomoku.utils;

import com.gomoku.model.Board;

import java.util.Arrays;

public class BoardEvaluator {

     // private int[][] grid; // 0: empty, 1: black (player), 2: white (AI)
    private int[][][] directionRecord = new int[15][15][4];     //directionRecord表示每个点上的四个方向是否已经访问了
    private int[][] count = new int[2][8];  //count二维数组记录黑棋和白棋的棋型个数统计
    private int[][] posScore = new int[15][15];  //pos_score 给棋盘上每个位置设一个初始分数，越靠近棋盘中心，分数越高，用来在最开始没有任何棋型时的，AI优先选取靠中心的位置。

    //获取己方(self)和对方(rival)在(row，col)处下棋的分数{selfScore,rivalScore}
    public int[] evaluatePointScore(int[][] grid, int row, int col, int self, int rival) {
        // 重置 count 数组
        for (int[] ints : count) {
            Arrays.fill(ints, 0);
        }

        // 模拟在当前点下己方棋子
        grid[row][col] = self;
        evaluatePoint(grid, row, col, self, rival, count[self - 1]);
        int[] selfCount = count[self - 1];

        // 模拟在当前点下对方棋子
        grid[row][col] = rival;
        evaluatePoint(grid, row, col, rival, self, count[rival - 1]);
        int[] rivalCount = count[rival - 1];

        // 恢复棋盘状态
        grid[row][col] = 0;

        // 分别计算己方和对手的分数
        int selfScore = getPointScore(selfCount);
        int  rivalScore = getPointScore(rivalCount);

        return new int[]{selfScore, rivalScore};
    }

    //根据count[]计算分数
    public int getPointScore(int[] count) {
        int score = 0;
        if (count[CountType.FIVE] > 0) {
            return Scores.FIVE;
        }
        if (count[CountType.LIVE_FOUR] > 0){
            return Scores.LIVE_FOUR;
        }
        // 如果只有一个冲四且没有活三的情况下，分数应较低，将其设置为活三的分数
        if(count[CountType.TO_FOUR] > 1){
            score += count[CountType.TO_FOUR] * Scores.TO_FOUR;
        }else if(count[CountType.TO_FOUR] > 0 && count[CountType.SLEEP_THREE] > 0){
            score += count[CountType.TO_FOUR] * Scores.TO_FOUR;
        }else if(count[CountType.TO_FOUR] > 0){
            score += Scores.LIVE_THREE;
        }

        if(count[CountType.LIVE_THREE] > 1){
            score += 5 * Scores.LIVE_THREE;
        }else if (count[CountType.LIVE_THREE] > 0) {
            score += Scores.LIVE_THREE;
        }

        if(count[CountType.SLEEP_THREE] > 0){
            score += count[CountType.SLEEP_THREE] * Scores.SLEEP_THREE;
        }
        if (count[CountType.LIVE_TWO] > 0){
            score += count[CountType.LIVE_TWO] * Scores.LIVE_TWO;
        }
        if (count[CountType.SLEEP_TWO] > 0){
            score += count[CountType.SLEEP_TWO] * Scores.SLEEP_TWO;
        }

        return score;
    }

    //对自身(self) (x, y) 点的 4 个主要方向进行点型分析。
    public void evaluatePoint(int[][] grid, int row, int col, int self, int rival, int[] count) {
        boolean ignoreRecord = (count != null); // 如果 count 非 null，则忽略记录
        if (count == null) {
            count = this.count[self - 1]; // 使用默认计数数组
        }
        // 方向偏移量：垂直，水平，主对角线、副对角线
        int[][] dirOffset = { {1, 0},{0, 1}, {1, 1}, {1, -1} };

        // 遍历 4 个方向
        for (int i = 0; i < 4; i++) {
            // 如果当前方向未被分析过，或忽略分析记录
            if (this.directionRecord[row][col][i] == 0 || ignoreRecord) {
                // 调用 analysisLine 方法分析该方向的棋型
                analysisLine(grid, row, col, i, dirOffset[i], self, rival, count);
            }
        }
    }

    //返回以(rwo,col)为中心的dirOffset方向上的连续的棋子序列
    public int[] getLine(int[][] grid, int row, int col, int[] dirOffset,int self,int rival) {
        int[] line = new int[9]; // 初始化长度为9的数组，代表该点在指定方向上的棋子序列

        int tempR = row - 4 * dirOffset[0]; // 起始点：以当前点 (row, col) 为中心向反方向偏移5步
        int tempC = col - 4 * dirOffset[1];

        for (int i = 0; i < 9; i++) {

            if (tempR < 0 || tempR >= Board.BOARD_SIZE || tempC < 0 || tempC >= Board.BOARD_SIZE) {
                // 超出棋盘范围，将该位置视为对手棋子
                line[i] =rival;
            } else {
                // 在棋盘范围内，直接读取棋子类型
                line[i] = grid[tempR][tempC];
            }
            tempR += dirOffset[0]; // 沿指定方向一步一步进
            tempC += dirOffset[1];
        }
        return line; // 返回长度为9的棋子序列
    }

    //分析一条线上的自身（self）旗型数量
    public int analysisLine(int[][] grid,int row,int col,int dirIndex,int[] dirOffset,int self,int rival,int[] count) {
        int empty = GridValueType.Grid_EMPTY.getValue();

        int leftIdx = 4;
        int rightIdx = 4;
        int[] line = getLine(grid, row, col, dirOffset, self, rival);

        //扩展右边
        while (rightIdx < 8) {
            if (line[rightIdx + 1] != self) break;
            rightIdx += 1;
        }
        //扩展左边
        while (leftIdx > 0) {
            if (line[leftIdx - 1] != self) break;
            leftIdx -= 1;
        }

        int leftRange = leftIdx;
        int rightRange = rightIdx;

        // 检查右边扩展
        while (rightRange < 8) {
            if (line[rightRange + 1] == rival) {
                break;
            }
            rightRange++;
        }
        // 检查左边扩展
        while (leftRange > 0) {
            if (line[leftRange - 1] == rival) {
                break;
            }
            leftRange--;
        }
        int chessRange = rightRange - leftRange + 1;
        //这部分已经不需要再去搜索了，因为没有可以落子的地方
        if (chessRange < 5) {
            setDirectionRecord(row, col, leftRange, rightRange, dirIndex, dirOffset);
            return CountType.NONE;
        }
        setDirectionRecord(row, col, leftIdx, rightIdx, dirIndex, dirOffset);

        int selfRange = rightIdx - leftIdx + 1;
        if (selfRange >= 5) {
            count[CountType.FIVE]++;
        }
        //计算以下两种情况的count
        //Live Four : XMMMMX
        //TO FOUR : XMMMMP, PMMMMX
        if (selfRange == 4) {
            boolean leftEmpty = false, rightEmpty = false;
            if (line[leftIdx - 1] == GridValueType.Grid_EMPTY.getValue()) {
                leftEmpty = true;
            }
            if (line[rightIdx + 1] == GridValueType.Grid_EMPTY.getValue()) {
                rightEmpty = true;
            }
            if (leftEmpty && rightEmpty) {
                count[CountType.LIVE_FOUR] += 1;
            } else if (leftEmpty || rightEmpty) {
                count[CountType.TO_FOUR] += 1;
            }
        }
        //计算以下三种情况的count
        //TO FOUR : XMXMMMX, XMMMXMX;
        //Live Three : XMMMXX, XXMMMX
        //Sleep Three: PMMMX, XMMMP, PXMMMXP
        if (selfRange == 3) {
            boolean leftEmpty = false, rightEmpty = false;
            boolean leftFour = false, rightFour = false;

            if (line[leftIdx - 1] == GridValueType.Grid_EMPTY.getValue()) {
                if (line[leftIdx - 2] == self) { // MXMMM
                    this.setDirectionRecord(row, col, leftIdx - 2, leftIdx - 1, dirIndex, dirOffset);
                    count[CountType.TO_FOUR] += 1;
                    leftFour = true;
                }
                leftEmpty = true;
            }

            if (line[rightIdx + 1] == GridValueType.Grid_EMPTY.getValue()) {
                if (line[rightIdx + 2] == self) { // MMMXM
                    setDirectionRecord(row, col, rightIdx + 1, rightIdx + 2, dirIndex, dirOffset);
                    count[CountType.TO_FOUR] += 1;
                    rightFour = true;
                }
                rightEmpty = true;
            }

            if (leftFour || rightFour) {
                // Do nothing
            } else if (leftEmpty && rightEmpty) {
                if (chessRange > 5) {
                    count[CountType.LIVE_THREE] += 1;  //PXMMMXXP, PXXMMMXP
                } else {
                    count[CountType.SLEEP_THREE] += 1;   //PXMMMXP
                }
            } else if (leftEmpty || rightEmpty) {      //PMMMXP, PXMMMP
                count[CountType.SLEEP_THREE] += 1;
            }
        }
        //Chong Four: MMXMM, only check right direction
        //Live Three: XMXMMX, XMMXMX the two types can both exist
        //Sleep Three: PMXMMX, XMXMMP, PMMXMX, XMMXMP
        //Live Two: XMMX
        //Sleep Two: PMMX, XMMP
        if (selfRange == 2) {
            boolean leftEmpty = false, rightEmpty = false;
            boolean leftThree = false, rightThree = false;

            if (line[leftIdx - 1] == GridValueType.Grid_EMPTY.getValue()) {
                if (line[leftIdx - 2] == self) {
                    setDirectionRecord(row, col, leftIdx - 2, leftIdx - 1, dirIndex, dirOffset);
                    if (line[leftIdx - 3] == GridValueType.Grid_EMPTY.getValue()) {
                        if (line[rightIdx + 1] == GridValueType.Grid_EMPTY.getValue()) {
                            count[CountType.LIVE_THREE] += 1;   // XMXMMX
                        } else {
                            count[CountType.SLEEP_THREE] += 1;  //XMXMMP
                        }
                        leftThree = true;
                    } else if (line[leftIdx - 3] == rival) {
                        if (line[rightIdx + 1] == GridValueType.Grid_EMPTY.getValue()) {
                            count[CountType.SLEEP_THREE] += 1;    //PMXMMX
                            leftThree = true;
                        }
                    }
                }
                leftEmpty = true;
            }
            if (line[rightIdx + 1] == GridValueType.Grid_EMPTY.getValue()) {
                if (line[rightIdx + 2] == self) {
                    if (line[rightIdx + 3] == self) {
                        this.setDirectionRecord(row, col, rightIdx + 1, rightIdx + 2, dirIndex, dirOffset);
                        count[CountType.TO_FOUR] += 1;   //MMXMM
                        rightThree = true;
                    } else if (line[rightIdx + 3] == GridValueType.Grid_EMPTY.getValue()) {
                        if (leftEmpty) {
                            count[CountType.LIVE_THREE] += 1;  //XMMXMX
                        } else {
                            count[CountType.SLEEP_THREE] += 1; //PMMXMX
                        }
                        rightThree = true;
                    } else if (leftEmpty) {
                        count[CountType.SLEEP_THREE] += 1;  //XMMXMP
                        rightThree = true;
                    }
                }
                rightEmpty = true;
            }
            if (leftThree || rightThree) {
                // Do nothing
            } else if (leftEmpty && rightEmpty) {
                count[CountType.LIVE_TWO] += 1;  //XMMX
            } else if (leftEmpty || rightEmpty) {
                count[CountType.SLEEP_TWO] += 1;  //XMMP,PMMX
            }
        }

        // Live Two: XMXMX, XMXXMX only check right direction
        // Sleep Two: PMXMX, XMXMP
        if (selfRange == 1) {
            boolean leftEmpty = false, rightEmpty = false;
            if (line[leftIdx - 1] == GridValueType.Grid_EMPTY.getValue()) {
                if (line[leftIdx - 2] == self) {
                    if (line[leftIdx - 3] == GridValueType.Grid_EMPTY.getValue()) {
                        if (line[rightIdx + 1] == rival) {
                            count[CountType.SLEEP_TWO] += 1;  //XMXMP
                        }
                    }
                }
                leftEmpty = true;
            }
            if (line[rightIdx + 1] == GridValueType.Grid_EMPTY.getValue()) {
                if (line[rightIdx + 2] == self) {
                    if (line[rightIdx + 3] == GridValueType.Grid_EMPTY.getValue()) {
                        if (leftEmpty) {
                            count[CountType.LIVE_THREE] += 1;  //XMXMX
                        } else {
                            count[CountType.SLEEP_TWO] += 1;  //PMXMX
                        }
                    }
                } else if (line[rightIdx + 2] == GridValueType.Grid_EMPTY.getValue()) {
                    if (line[rightIdx + 3] == self) {
                        if (line[rightIdx + 4] == GridValueType.Grid_EMPTY.getValue() && leftEmpty) {
                            count[CountType.LIVE_TWO] += 1;   //XMMXMX
                        }else if(line[rightIdx + 4] == GridValueType.Grid_EMPTY.getValue() || leftEmpty){
                            count[CountType.SLEEP_TWO] += 1;  //XMXXMP,PMXXMX
                        }
                    }
                }
            }
        }
        return CountType.NONE;
    }

    public void setDirectionRecord(int row,int col,int left,int right,int dirIndex,int[] dirOffset){
        int tempR = row + (-4+left) * dirOffset[0];
        int tempC = col + (-4+left) * dirOffset[1];
        for(int i = left; i<= right;i++){
            this.directionRecord[tempR][tempC][dirIndex] = 1;
            tempR += dirOffset[0];
            tempC += dirOffset[1];
        }
    }

    // 主评估函数,返回自身（self）棋盘分数-对手（rival）棋盘分数的值
    public int evaluate(Board board, int self,int rival,boolean checkWin) {
        reset(); // 重置评估器状态
        int[][] grid = board.getGrid();

        // 遍历棋盘
        for (int row = 0; row < Board.BOARD_SIZE; row++) {
            for (int col = 0; col < Board.BOARD_SIZE; col++) {
                if (grid[row][col] == self) {
                    evaluatePoint(grid, row, col, self, rival,null); // 评估当前玩家的点
                } else if (grid[row][col] == rival) {
                    evaluatePoint(grid, row, col, rival, self,null); // 评估对手的点
                }
            }
        }
        int[] selfCount = count[self - 1];
        int[] rivalCount = count[rival - 1];

        // 检查是否获胜
        if (checkWin) {
            return (selfCount[CountType.FIVE] > 0) ? 1 : 0; // 如果自身有五连珠，返回胜利标志
        } else {
            int[] scores = getScore(selfCount, rivalCount);
            int selfScore = scores[0];
            int rivalScore = scores[1];
            return selfScore - rivalScore; // 返回分数差
        }
    }

    // 计算得分
    //计算自身（selfCount）和对手（rivalCount）的得分
    public int[] getScore(int[] selfCount, int[] rivalCount) {
        int selfScore = 0; // 当前玩家得分
        int rivalScore = 0; // 对手得分

        // 检查五连珠
        if (selfCount[CountType.FIVE] > 0) {
            return new int[]{Scores.FIVE, 0};
        }
        if (rivalCount[CountType.FIVE] > 0) {
            return new int[]{0, Scores.FIVE};
        }

        // 检查双冲四升为活四
        if (selfCount[CountType.TO_FOUR] >= 2) {
            selfCount[CountType.LIVE_FOUR]++;
        }
        if (rivalCount[CountType.TO_FOUR] >= 2) {
            rivalCount[CountType.LIVE_FOUR]++;
        }

        // 检查活四和冲四
        if (selfCount[CountType.LIVE_FOUR] > 0) {
            return new int[]{9050, 0};
        }
        if (selfCount[CountType.TO_FOUR] > 0) {
            return new int[]{9040, 0};
        }

        if (rivalCount[CountType.LIVE_FOUR] > 0) {
            return new int[]{0, 9030};
        }
        if (rivalCount[CountType.TO_FOUR] > 0 && rivalCount[CountType.LIVE_THREE] > 0) {
            return new int[]{0, 9020};
        }

        // 检查活三
        if (selfCount[CountType.LIVE_THREE] > 0 && rivalCount[CountType.TO_FOUR] == 0) {
            return new int[]{9010, 0};
        }

        // 检查对手双活三的威胁
        if (rivalCount[CountType.LIVE_THREE] > 1 && selfCount[CountType.LIVE_THREE] == 0 && selfCount[CountType.SLEEP_THREE] == 0) {
            return new int[]{0, 9000};
        }

        // 冲四得分
        if (rivalCount[CountType.TO_FOUR] > 0) {
            rivalScore += 400;
        }

        // 活三得分
        if (selfCount[CountType.LIVE_THREE] > 1) {
            selfScore += 500;
        } else if (selfCount[CountType.LIVE_THREE] > 0) {
            selfScore += 100;
        }

        if (rivalCount[CountType.LIVE_THREE] > 1) {
            rivalScore += 2000;
        } else if (rivalCount[CountType.LIVE_THREE] > 0) {
            rivalScore += 400;
        }

        // 眠三得分
        if (selfCount[CountType.SLEEP_THREE] > 0) {
            selfScore += selfCount[CountType.SLEEP_THREE] * 10;
        }
        if (rivalCount[CountType.SLEEP_THREE] > 0) {
            rivalScore += rivalCount[CountType.SLEEP_THREE] * 10;
        }

        // 活二得分
        if (selfCount[CountType.LIVE_TWO] > 0) {
            selfScore += selfCount[CountType.LIVE_TWO] * 6;
        }
        if (rivalCount[CountType.LIVE_TWO] > 0) {
            rivalScore += rivalCount[CountType.LIVE_TWO] * 6;
        }

        // 眠二得分
        if (selfCount[CountType.SLEEP_TWO] > 0) {
            selfScore += selfCount[CountType.SLEEP_TWO] * 2;
        }
        if (rivalCount[CountType.SLEEP_TWO] > 0) {
            rivalScore += rivalCount[CountType.SLEEP_TWO] * 2;
        }

        return new int[]{selfScore, rivalScore};
    }

    // 重置评估器状态
    public void reset(){
        // 初始化 directionRecord 三维数组，所有值为 0
        for (int i = 0; i < directionRecord.length; i++) {
            for (int j = 0; j < directionRecord.length; j++) {
                for (int k = 0; k < 4; k++) {
                    directionRecord[i][j][k] = 0;
                }
            }
        }
        // 初始化 count 二维数组，所有值为 0
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < count.length; j++) {
                count[i][j] = 0;
            }
        }

        // 初始化 posScore 二维数组
        for (int row = 0; row < 15; row++) {
            for (int col = 0; col < 15; col++) {
                posScore[row][col] = 7 - Math.max(Math.abs(row - 7), Math.abs(col - 7));
            }
        }
    }
}
